﻿#include "../StdAfx.h"
#include "BluesoleilInterface.h"

BluesoleilInterface* currentInstance;
	// ===== SDK Functions
	// Init and Stop
	BTSDKVOID		SDK_Init;
	BTSDKVOID		SDK_Done;
	BTSDKVOID		SDK_StartBluetooth;
	BTSDKVOID		SDK_StopBluetooth;
	// Search for Devices
	BTDISCOVER		SDK_StartDeviceDiscovery;
	// Misc
	BTREGISTER		SDK_RegisterCallback4ThirdParty;
	// Get Info
	BTADDRESS	SDK_GetRemoteDeviceAddress;
	BTNAME		SDK_GetRemoteDeviceName;
	BTNAME		SDK_UpdateRemoteDeviceName;
	// Pairing
	BTPAIR		SDK_PairDevice;
	BTPAIR		SDK_UnPairDevice;
	BTISPAIRED	SDK_IsDevicePaired;
	// Connection
	BTSDKVOID	SDK_StartEnumConnection;
	BTENUMCONN	SDK_EnumConnection;
	BTSDKVOID	SDK_EndEnumConnection;
	BTGETPORT	SDK_GetClientPort;


BluesoleilInterface::BluesoleilInterface(void)
{
		currentInstance = this;
		activeConnection = BTSDK_INVALID_HANDLE;
		btSocket = INVALID_SOCKET;
		comPortIndex = 0;
		serialEye.setRxSize(SERIAL_BUFFER_CAPACITY);
}

BluesoleilInterface::~BluesoleilInterface(void)
{
	if( blueSoleilDLL != NULL )
	{
		SDK_StopBluetooth();
		SDK_Done();
	}
}

// ======================================================================================
/// \brief Iniţializează Bluesoleil
///	- încarcă librăria bluesoleil i.e. 'bssdk.dll' şi obţine handlere la funcţiile ei
///	- aplează funcţiile librărie <i> Btsdk_Init </i> şi <i> Btsdk_StartBluetooth </i>
/// - asociază funcţii de tratare a evenimentelor bluetooth i.e. <i> Un echipament este
///	disponibil </i>
// ======================================================================================
RESULT BluesoleilInterface::InitBluetooth()
{
	// ==================================================================================
	// First thing to do, considering the Bluesoleil implementation, is to
	// Load the DLL.
	blueSoleilDLL = LoadLibrary( DLL_NAME );
	
	if( blueSoleilDLL == NULL )
	{
		MessageBox(NULL, _T("Install Blusoleil 5.1 or newer"), _T("Required"), MB_OK);
		return FAILED;
	}
	
	// Load the functions from DLL
	GetFunctionsFromDll();
	
	if( SDK_Init() != BTSDK_OK )
	{
		MessageBox(NULL, _T("Can't initialise Bluetooth!"), _T("Have no ideea why!"), MB_OK);
		return FAILED;
	}

	if( SDK_StartBluetooth() != BTSDK_OK )
	{
		MessageBox(NULL, _T("Can't start Bluetooth!"), _T("Have no ideea why!"), MB_OK);
		return FAILED;
	}
			
	RegisterEventHandlers();

	// Alte iniţializări...
	searchCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
	return OK;
}

// ======================================================================================
//	Initializing SDK functions for Bluesoleil
// ======================================================================================
void	BluesoleilInterface::GetFunctionsFromDll()
{
	SDK_Init =							(BTSDKVOID)	GetProcAddress( blueSoleilDLL, "Btsdk_Init");
	SDK_Done =							(BTSDKVOID)	GetProcAddress( blueSoleilDLL, "Btsdk_Done");
	SDK_StartBluetooth =					(BTSDKVOID)	GetProcAddress( blueSoleilDLL, "Btsdk_StartBluetooth");
	SDK_StopBluetooth =					(BTSDKVOID)	GetProcAddress( blueSoleilDLL, "Btsdk_StopBluetooth");
	SDK_StartDeviceDiscovery =			(BTDISCOVER)GetProcAddress( blueSoleilDLL, "Btsdk_StartDeviceDiscovery");
	SDK_RegisterCallback4ThirdParty =	(BTREGISTER)GetProcAddress( blueSoleilDLL, "Btsdk_RegisterCallback4ThirdParty");
	SDK_GetRemoteDeviceAddress =			(BTADDRESS)	GetProcAddress( blueSoleilDLL, "Btsdk_GetRemoteDeviceAddress");
	SDK_GetRemoteDeviceName =			(BTNAME)	GetProcAddress( blueSoleilDLL, "Btsdk_GetRemoteDeviceName");
	SDK_UpdateRemoteDeviceName =			(BTNAME)	GetProcAddress( blueSoleilDLL, "Btsdk_UpdateRemoteDeviceName");
	SDK_PairDevice =						(BTPAIR)	GetProcAddress( blueSoleilDLL, "Btsdk_PairDevice");
	SDK_UnPairDevice =					(BTPAIR)	GetProcAddress( blueSoleilDLL, "Btsdk_UnPairDevice");
	SDK_IsDevicePaired =					(BTISPAIRED)GetProcAddress( blueSoleilDLL, "Btsdk_IsDevicePaired");
	SDK_StartEnumConnection =			(BTSDKVOID)	GetProcAddress( blueSoleilDLL, "Btsdk_StartEnumConnection");
	SDK_EnumConnection =					(BTENUMCONN)GetProcAddress( blueSoleilDLL, "Btsdk_EnumConnection");
	SDK_EndEnumConnection  =				(BTSDKVOID)	GetProcAddress( blueSoleilDLL, "Btsdk_EndEnumConnection");
	SDK_GetClientPort =						(BTGETPORT) GetProcAddress( blueSoleilDLL, "Btsdk_GetClientPort");

}
// ======================================================================================
///	\brief Implementarea Bluesoleil pentru căutarea de echipamente
///	- Lansează funcţia librărie <i> Btsdk_StartDeviceDiscovery </i>
///	- Aşteaptă primirea evenimentului de terminare a căutării şi populează lista cu 
/// echipamente găsite
// ======================================================================================
RESULT BluesoleilInterface::SearchDevices()
{
	foundDevicesCount = 0;
	if( SDK_StartDeviceDiscovery( 0, MAX_DEVICES, SEARCH_TIME ) == BTSDK_OK )
	{
		WaitForSingleObject( searchCompleteEvent, INFINITE );
		// ====== Getting device info
		for(int i = 0; i < foundDevicesCount; i++)
		{
			if( SDK_GetRemoteDeviceName( deviceID[i], (BTUINT8*) deviceName, NULL)
			!= BTSDK_OK )
			{
				if( SDK_UpdateRemoteDeviceName( deviceID[i], (BTUINT8*) deviceName, NULL )
				!= BTSDK_OK )
				{
					strcpy_s( deviceName, "Unknown" );
				}
			}
			MultiByteToWideChar(CP_ACP, 0, deviceName, -1, Devices[i].Name , NAME_LENGTH);
			SDK_GetRemoteDeviceAddress( deviceID[i], Devices[i].AddressString );
			SDK_IsDevicePaired( deviceID[i ], & Devices[i].IsPaired );
		}
		
	}
	return OK;
}
// ======================================================================================
//	Tratarea găsirii unui echipament
// ======================================================================================
void BluesoleilInterface::FoundDevice(BTDEVHDL dev_hdl)
{
	if( currentInstance != NULL &&							// Bluesoleil works
		currentInstance->foundDevicesCount < MAX_DEVICES)	// Not found too many devices
	{
		currentInstance->deviceID[ currentInstance->foundDevicesCount ] = dev_hdl;
		currentInstance->foundDevicesCount++;
	}
}

// ======================================================================================
// Evenimentul de Conectare/Deconectare
// ======================================================================================
void BluesoleilInterface::ConnectionDog(BTCONNHDL connection, BTUINT16 connEvent, BTUINT8* arg)
{
	switch( connEvent )
	{
	// ===== Device connected on communcication socket
	case BTSDK_APP_EV_CONN_IND:
		if( currentInstance->activeConnection == BTSDK_INVALID_HANDLE &&
			((PBtSdkConnectionPropertyStru) arg) -> service_class == BTSDK_CLS_SERIAL_PORT)
		{
			currentInstance->activeConnection = connection;
			memcpy( & (currentInstance->activeConnectionInfo) , 
					(PBtSdkConnectionPropertyStru) arg , 
					sizeof(BtSdkConnectionPropertyStru));
			currentInstance->comPortIndex = SDK_GetClientPort( connection );
			currentInstance->Connect( currentInstance->comPortIndex );
		}
		break;
	// ===== Device says Bye bye from socket connection!
	case BTSDK_APP_EV_DISC_IND:
		if( currentInstance->activeConnection == connection )
		{
			currentInstance->activeConnection = BTSDK_INVALID_HANDLE;
			memcpy( & (currentInstance->activeConnectionInfo) , 
					(PBtSdkConnectionPropertyStru) arg , 
					sizeof(BtSdkConnectionPropertyStru));
			currentInstance->Disconnect(0);
		}
		break;
	case BTSDK_APP_EV_CONN_CFM:
		break;
	case BTSDK_APP_EV_DISC_CFM:
		break;
	}
}
// ======================================================================================
//	Search completed
// ======================================================================================
void BluesoleilInterface::SearchComplete()
{
	SetEvent( currentInstance->searchCompleteEvent );
}

// ======================================================================================
//	Asignez funcţii de tratare a evenimentelor
// ======================================================================================
void BluesoleilInterface::RegisterEventHandlers()
{
	BtSdkCallbackStru eventTube = {0};
	
	// Event : Device responded to discovery
	eventTube.type = BTSDK_INQUIRY_RESULT_IND;
	eventTube.func = (void*)FoundDevice;
	SDK_RegisterCallback4ThirdParty( &eventTube );
	
	// Event : Discovery complete
	eventTube.type = BTSDK_INQUIRY_COMPLETE_IND;
	eventTube.func = (void*) SearchComplete;
	SDK_RegisterCallback4ThirdParty( &eventTube );

	// Event : Connection event
	eventTube.type = BTSDK_CONNECTION_EVENT_IND;
	eventTube.func = (void*) ConnectionDog;
	SDK_RegisterCallback4ThirdParty( &eventTube );
}
// ======================================================================================
/// \brief Implementarea bluesoleil
///	Se conectează direct la portul virtual serial instalat de Bluesoleil în sistem
///	\param activePort	Indexul portului serial i.e. pentru COM3 activePort = 3
// ======================================================================================
RESULT BluesoleilInterface::Connect(UINT8 activePort)
{
	if( activeConnection != BTSDK_INVALID_HANDLE )
	{
		wsprintf(portName, _T("COM%d"), activePort );
		int result = serialEye.connect(portName, 19200, SERIAL_PARITY_NONE, 8, true);
		printf("p");
	}
	return OK;
}
// ======================================================================================
/// \brief Închide comunicaţia serială
// ======================================================================================
RESULT BluesoleilInterface::Disconnect(UINT8 index)
{
	serialEye.disconnect();
	return OK;
}
// ======================================================================================
/// \brief Implementare Bluesoleil
// ======================================================================================
RESULT BluesoleilInterface::Send(BYTE* data, UINT16 length)
{
	// Nu este necesară, deoarece PCul nu trimite date
	return OK;
}
// ======================================================================================
/// \brief Implementare Bluesoleil
// ======================================================================================
RESULT BluesoleilInterface::Receive(char* data, UINT16 length)
{
	return OK;
}
